﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using TimScripts.BF4Rcon.Frostbite;

namespace TimScripts.BF4Rcon
{
    public class MapCollection : IMapCollection, IList<IMap>
    {
        private ISynchronousRconClient Client;

        public IMap this[int index]
        {
            get
            {
                if (!Client.IsLoggedOn)
                    throw new NotLoggedOnException();

                MapDataMapCollection maps = GetMaps(index);
                IMap result;

                if (maps.Count == 0)
                    throw new ArgumentOutOfRangeException("index");

                result = maps[0];

                return result;
            }
            set
            {
                throw new NotImplementedException(); //failing a test
                RemoveAt(index);
                Insert(index, value);
            }
        }

        public int Count
        {
            get
            {
                if (!Client.IsLoggedOn)
                    throw new NotLoggedOnException();

                IEnumerable<MapDataMapCollection> mapResponses = GetMapResponses();
                int count = 0;

                foreach (var mapData in mapResponses)
                {
                    count += mapData.Count;
                }

                return count;
            }
        }

        public IEnumerator<IMap> GetEnumerator()
        {
            if (!Client.IsLoggedOn)
                throw new NotLoggedOnException();

            IEnumerable<MapDataMapCollection> mapResponses = GetMapResponses();

            foreach (MapDataMapCollection data in mapResponses)
            {
                foreach (Map map in data)
                {
                    yield return map;
                }
            }
        }

        public MapCollection(ISynchronousRconClient client)
        {
            Client = client;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public int IndexOf(IMap item)
        {
            throw new NotImplementedException();
        }

        public void Insert(int index, IMap item)
        {
            string mapName;
            string gameMode;
            int rounds;
            IList<string> result;

            if (!Client.IsLoggedOn)
                throw new NotLoggedOnException();

            CheckMapValidity(item);

            mapName = item.RawMapName;
            gameMode = item.RawModeName;
            rounds = item.RoundsToPlay;

            if (rounds < 1)
                rounds = 1;

            result = SendRequest("mapList.add", mapName, gameMode, rounds.ToString(CultureInfo.InvariantCulture), index.ToString(CultureInfo.InvariantCulture));

            if (result[0].Equals("InvalidMapIndex"))
                throw new ArgumentOutOfRangeException("index");
        }

        public void RemoveAt(int index)
        {
            if (!Client.IsLoggedOn)
                throw new NotLoggedOnException();

            IList<string> result = SendRequest("mapList.remove", index.ToString(CultureInfo.InvariantCulture));

            if (result[0].Equals("InvalidMapIndex"))
                throw new ArgumentOutOfRangeException("index");
        }

        public void Add(IMap item)
        {
            string mapName;
            string gameMode;
            int rounds;

            if (!Client.IsLoggedOn)
                throw new NotLoggedOnException();

            CheckMapValidity(item);

            mapName = item.RawMapName;
            gameMode = item.RawModeName;
            rounds = item.RoundsToPlay;

            if (rounds < 1)
                rounds = 1;

            SendRequest("mapList.add", mapName, gameMode, rounds.ToString(CultureInfo.InvariantCulture));
        }

        public void Clear()
        {
            throw new NotImplementedException();
        }

        public bool Contains(IMap item)
        {
            throw new NotImplementedException();
        }

        public void CopyTo(IMap[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(IMap item)
        {
            throw new NotImplementedException();
        }

        private IList<string> SendRequest(params string[] words)
        {
            return Client.SendRequest(words);
        }

        private void CheckMapValidity(IMap item)
        {
            if (item == null)
                throw new ArgumentNullException("item");

            if (item.MapName == MapName.Unknown)
                throw new UnknownMapNameException();

            if (item.GameMode == GameMode.Unknown)
                throw new UnknownGameModeException();
        }

        private IEnumerable<MapDataMapCollection> GetMapResponses()
        {
            int offset = 0;
            MapDataMapCollection currentMaps;

            do
            {
                currentMaps = GetMaps(offset);

                offset += currentMaps.Count;

                yield return currentMaps;

            } while (currentMaps.Count > 0);
        }

        private MapDataMapCollection GetMaps(int offset)
        {
            IList<string> response = Client.SendRequest(GetRequest(offset));
            MapDataMapCollection maps = new MapDataMapCollection(response, 1);

            return maps;
        }

        private IEnumerable<string> GetRequest(int offset)
        {
            return new string[] { "mapList.list", offset.ToString(CultureInfo.InvariantCulture) };
        }
    }
}
